// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#pragma once

#include <cstdint>
#include <string>
#include <turbo/utility/status.h>
#include <cantor/proto/type.pb.h>

namespace cantor {

    /// Cantor type system supports a small set of SQL-compatible composeable types:
    /// BOOLEAN, TINYINT, SMALLINT, INTEGER, BIGINT, HUGEINT, REAL, DOUBLE, VARCHAR,
    /// VARBINARY, TIMESTAMP, ARRAY, MAP, ROW
    ///
    /// This file has multiple C++ type definitions for each of these logical types.
    /// These logical definitions each serve slightly different purposes.
    /// These type sets are:
    /// - pb::TypeKind
    /// - Type (RowType, BigIntType, ect.)
    /// - Templated Types (Row<T...>, Map<K, V>, ...)
    ///     C++ templated classes. Never instantiated, used to pass limited type
    ///     information into template parameters.

    /// Simple enum with type category.
    ///
    /*
    enum class pb::TypeKind : int8_t {
        NONE = 0,
        PRIMITIVE_MIN = 1,
        INT8 = 1,
        INT16 = 2,
        INT32 = 3,
        INT64 = 4,
        INT128 = 5,
        UINT8  = 6,
        UINT16 = 7,
        UINT32 = 8,
        UINT64 = 9,
        UINT128 = 10,
        FP8 = 11,
        FP16 = 12,
        FP32 = 13,
        FP64 = 14,
        STRING = 15,
        BINARY = 16,
        TIMESTAMP = 17,
        DURATION = 18,
        BOOLEAN = 19,
        DATETIME = 20,
        INTERVAL = 21,
        DECIMAL64 = 22,
        DECIMAL128 = 23,
        ENUM = 24,
        PRIMITIVE_MAX = 24,

        // Enum values for ComplexTypes start after 30 to leave
        // some values space to accommodate adding new scalar/native
        // types above.
        COMPLEX_MIN = 30,
        ARRAY = 30,
        MAP = 31,
        HASHMAP = 32,
        SET =33,
        HASHSET =34,
        STRUCT = 35,
        TUPLE = 36,
        UNION = 37,
        FUNCTION = 38,
        ROW = 39,
        UDF = 40,
        JSON = 41,
        PROTO = 42,
        COMPLEX_MAX = 42,
        TYPE_MAX = 42
    };

    */
    std::ostream &operator<<(std::ostream &os, const pb::TypeKind &kind);

    /// Returns the type kind represented by the `name`. Throws if no match found.
    /// if not found. if will be return pb::TypeKind::NONE
    pb::TypeKind map_name_to_type_kind(const std::string &name);

    constexpr bool is_valid_type_kind(pb::TypeKind kind) {
        return kind >= pb::TypeKind::TYPE_KIND_PRIMITIVE_MIN && kind <= pb::TypeKind::TYPE_KIND_PRIMITIVE_MAX && kind >= pb::TypeKind::TYPE_KIND_COMPLEX_MIN && kind <= pb::TypeKind::TYPE_KIND_COMPLEX_MAX;
    }

    /// if not valid , got "NONE" result
    std::string map_type_kind_to_name(const pb::TypeKind &typeKind);

    template<typename Sink>
    void turbo_stringify(Sink &s, const pb::TypeKind &kind) {
        s.Append(map_type_kind_to_name(kind));
    }

}  // namespace cantor
